package com.easygoods.service;

import com.bestvike.stone.core.lang.Convert;
import com.bestvike.stone.core.lang.Environment;
import com.bestvike.stone.core.lang.ThrowableUtils;
import com.bestvike.stone.spring.concurrent.DistributedLock;
import com.bestvike.stone.spring.concurrent.LockFailedException;
import com.bestvike.stone.spring.concurrent.LockObject;
import com.bestvike.stone.spring.exception.BusinessException;
import com.bestvike.stone.spring.mail.bugreport.BugReportLevel;
import com.bestvike.stone.spring.mail.bugreport.BugReportUtils;
import com.bestvike.stone.spring.service.BaseService;
import com.easygoods.bean.PayOrderBean;
import com.easygoods.bean.PayOrderResultBean;
import com.easygoods.dao.PayRecordDao;
import com.easygoods.entity.PayRecord;
import com.easygoods.enums.YNEnum;
import lombok.extern.apachecommons.CommonsLog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

/**
 * Created by 许崇雷 on 2019-01-24.
 */
@CommonsLog
@Service
public class OrderPayService extends BaseService {
    private static final String PAYING_ORDER_PREFIX = "PAYING:";//支付中订单
    @Autowired
    private PayRecordDao payRecordDao;
    @Autowired
    private OrderService orderService;

    //支付,不需要开启事务,只有支付成功才返回 true
    public PayOrderResultBean payOrder(PayOrderBean payOrderBean) {
        //验证参数
        Assert.notNull(payOrderBean, "payOrderBean can not be null");
        payOrderBean.assertValid();

        final String orderId = payOrderBean.getOrderId();
        //加锁,防止并发支付
        try (LockObject ignored = DistributedLock.lock(PAYING_ORDER_PREFIX + orderId)) {
            final PayRecord payRecord = this.payRecordDao.selectByPrimaryKey(payOrderBean.getPayTradeNo());//已确认支付宝和微信的单号不可能重复
            if (payRecord == null) {
                //插入 pay_record 表 finish 为 N 如果重复丢弃
                PayRecord payRecordInsert = payOrderBean.toPayRecord();
                payRecordInsert.beforeInsert();
                int payRecordNum = this.payRecordDao.insert(payRecordInsert);
                if (payRecordNum != 1) {
                    log.info("插入支付记录表失败 orderId:" + orderId);
                    return new PayOrderResultBean(false, "新增支付记录失败");
                }
            } else if (Convert.toType(payRecord.getFinish(), YNEnum.class) == YNEnum.Y) {
                log.info("该定单已经支付,跳过处理 orderId:" + orderId);
                return new PayOrderResultBean(true, "已经处理过");
            }
            this.orderService.payOrder(payOrderBean);
            return new PayOrderResultBean(true, "处理成功");
        } catch (LockFailedException e) {
            log.info("同一个订单发生并发支付 orderId:" + orderId);
            BugReportUtils.sendAsync(BugReportLevel.INFO, "[支付通知接口] 同一个订单发生并发支付 orderId:" + orderId);
            return new PayOrderResultBean(false, "该订单正在处理");
        } catch (BusinessException e) {
            log.info("支付通知处理失败:" + e.getMsg());
            return new PayOrderResultBean(false, "该订单处理失败:" + e.getMsg());
        } catch (Exception e) {
            log.error("支付通知处理失败", e);
            BugReportUtils.sendAsync(BugReportLevel.INFO, "[支付通知接口] 处理失败 orderId:" + orderId + Environment.NewLine + ThrowableUtils.getString(e));
            return new PayOrderResultBean(false, "该订单处理失败");
        }
    }
}
